package com.jmonkey.office.jwp;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.beans.PropertyVetoException;
import java.io.File;
import java.io.IOException;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultDesktopManager;
import javax.swing.DesktopManager;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JInternalFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;

import com.jmonkey.export.Registry;
import com.jmonkey.export.Runtime;
import com.jmonkey.office.jwp.DynamicFileFilter;
import com.jmonkey.office.jwp.support.Code;
import com.jmonkey.office.jwp.support.Editor;
import com.jmonkey.office.jwp.support.FileActionListener;
import com.jmonkey.office.jwp.support.Mime;

/**
 * This class manages the active document frames in the JWP application.
 */
public final class DocumentManager extends DefaultDesktopManager implements
    DesktopManager, FileActionListener {

  private JWP _jwpApplication = null;
  private Registry _registry = null;
  private DocumentFrame _activeDocumentFrame = null;
  private String _documentsDirectoryPath = null;

  private final String _newDocumentTitle;

  public DocumentManager(JWP parent) {
    super();
    _jwpApplication = parent;
    _registry = parent.getRegistry();
    _newDocumentTitle = _registry.getString("MAIN", "new.document.title");
    _documentsDirectoryPath = _registry.getString("USER", "default.documents.directory");
    Runtime.ensureDirectory(_documentsDirectoryPath);
    init();
  }

  public void editorNew() {
    Code.debug("editorNew");
    createDocumentFrame();
  }

  public void editorOpen(File file) {
    Code.debug("editorOpen(File)");
    if (file != null) {        
      String mime = Mime.findContentType(file);
      try {
        if (!file.exists()) { //(DARREN)
            throw new IOException("File does not exist.");
        }

        DocumentFrame doc = createDocumentFrame(null, file.getName(), mime);
        Editor ed = doc.getEditor();
        ed.read(file);
        ed.setFile(file);
        _jwpApplication.addToFileHistory(file);
      }
      catch (IOException ioe0) {
        showException(ioe0);
      }
    }
  }

  public void editorOpen() {
    Code.debug("editorOpen");

    JFileChooser chooser = new JFileChooser();
    chooser.setDialogTitle(JWP.getMessage("dialog.open.title"));
    chooser.setDialogType(JFileChooser.OPEN_DIALOG);
    chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

    FileFilter filter = null;
    filter = new DynamicFileFilter("java c cc cpp h txt text",
        "filter.plain.label");
    chooser.addChoosableFileFilter(filter);
    filter = new DynamicFileFilter("rtf", "filter.rtf.label");
    chooser.addChoosableFileFilter(filter);
    filter = new DynamicFileFilter("htm html shtml", "filter.html.label");
    chooser.addChoosableFileFilter(filter);
    filter = chooser.getAcceptAllFileFilter();
    chooser.addChoosableFileFilter(filter);

    chooser.setCurrentDirectory(new File(_documentsDirectoryPath));

    int result = chooser.showOpenDialog(_jwpApplication);
    _documentsDirectoryPath = chooser.getCurrentDirectory().getAbsolutePath();

    if (result == JFileChooser.APPROVE_OPTION) {
        editorOpen(chooser.getSelectedFile());
    }

  }

  public void editorOpenAs() {
    Code.debug("editorOpenAs");

    JFileChooser chooser = new JFileChooser();
    chooser.setDialogTitle(JWP.getMessage("dialog.openas.title"));
    chooser.setDialogType(JFileChooser.OPEN_DIALOG);
    chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

    FileFilter plainFilter =
      new DynamicFileFilter("*", "filter.any.plain.label");
    chooser.addChoosableFileFilter(plainFilter);
    FileFilter rtfFilter =
      new DynamicFileFilter("*", "filter.any.rtf.label");
    chooser.addChoosableFileFilter(rtfFilter);
    FileFilter htmlFilter =
      new DynamicFileFilter("*", "filter.any.html.label");
    chooser.addChoosableFileFilter(htmlFilter);
    FileFilter allFilter = chooser.getAcceptAllFileFilter();
    chooser.addChoosableFileFilter(allFilter);

    chooser.setCurrentDirectory(new File(_documentsDirectoryPath));
    int result = chooser.showOpenDialog(_jwpApplication);
    _documentsDirectoryPath = chooser.getCurrentDirectory().getAbsolutePath();

    if (result != JFileChooser.APPROVE_OPTION) {
        return;
    }

    File fileToOpen = chooser.getSelectedFile();
    if (fileToOpen != null) {
      FileFilter filterUsed = chooser.getFileFilter();
      String mime = (filterUsed == plainFilter) ? "text/plain" :
        (filterUsed == rtfFilter) ? "text/rtf" :
        (filterUsed == htmlFilter) ?"text/html" : "text/plain";
      try {
        DocumentFrame df =
          createDocumentFrame(null, fileToOpen.getName(), mime);
        df.getEditor().read(fileToOpen);
        _jwpApplication.addToFileHistory(fileToOpen);
      }
      catch (IOException ioe0) {
        showException(ioe0);
      }
    }
  }

  public void editorRevert(Editor editor) {
    Code.debug("editorRevert");
    if (editor.getFile() == null) {
      String msg = JWP.getMessage("dialog.revert.warning.0");
      JOptionPane.showMessageDialog(_jwpApplication, msg, "Bad State",
                                    JOptionPane.ERROR_MESSAGE);
    }
    else {
      String msg = JWP.getMessage("dialog.revert.warning.1");
      String query = JWP.getMessage("dialog.revert.query");
      int answer = JOptionPane.showConfirmDialog(getParent(), msg,
          query, JOptionPane.YES_NO_CANCEL_OPTION,
          JOptionPane.WARNING_MESSAGE);
      if (answer == JOptionPane.YES_OPTION) {
        if (!editor.isEmpty()) {
          editor.getTextComponent().setText("");
        }
        try {
          editor.read(editor.getFile());
        }
        catch (IOException ioe0) {
          showException(ioe0);
        }
      }
    }
  }

  public void editorSave(Editor editor) { // darren
      editorSave(editor, _activeDocumentFrame);
  }

  public void editorSave(Editor editor, DocumentFrame frame) { // darren
    Code.debug("editorSave");
    
    if (frame == null) {
        return;
    }
    try {
      if (editor.getFile() == null) {
          editorSaveAs(editor, frame);
          //atk: call saveas instead of duplicating all the code
//        JFileChooser chooser =
//          new JFileChooser(JWP.getMessage("dialog.save.title"));
//        chooser.setDialogType(JFileChooser.SAVE_DIALOG);
//        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
//        chooser.setCurrentDirectory(new File(_documentsDirectoryPath));
//
//        String ct = editor.getContentType();
//        configureFileType(chooser, ct);
//        int result = chooser.showSaveDialog(_jwpApplication);
//        _documentsDirectoryPath = chooser.getCurrentDirectory().getAbsolutePath();
//
//        if (result != JFileChooser.APPROVE_OPTION) {
//            return;
//        }
//        
//        File fileToOpen = chooser.getSelectedFile();
//        if (fileToOpen.exists()) {
//            int answer = JOptionPane.showConfirmDialog(_jwpApplication, 
//                    "Overwrite existing file?",
//                "File exists.", JOptionPane.OK_CANCEL_OPTION,
//                JOptionPane.WARNING_MESSAGE);
//            if (answer != JOptionPane.OK_OPTION) {
//                return;
//            }
//        }
//        
//        String mime = Mime.findContentType(fileToOpen);
//
//          if (!ct.equals(mime)) {
//            String msg = JWP.getMessage("dialog.save.warning.0");
//            String query = JWP.getMessage("dialog.save.query");
//            int answer = JOptionPane.showConfirmDialog(_jwpApplication, msg,
//                query, JOptionPane.YES_NO_CANCEL_OPTION,
//                JOptionPane.WARNING_MESSAGE);
//            if (answer == JOptionPane.YES_OPTION) {
//              editor.write(fileToOpen);
//              editor.setFile(fileToOpen);
//              frame.setTitle(fileToOpen.getName());
//                editor.setChanged(false);
//                _jwpApplication.addToFileHistory(fileToOpen);
//            }
//          }
//          else {
//            editor.write(fileToOpen);
//            editor.setFile(fileToOpen);
//            frame.setTitle(fileToOpen.getName());
//          }
//        editor.setChanged(false);
//        _jwpApplication.addToFileHistory(fileToOpen);
      }
      else if (editor.isNew() || editor.isChanged()) {
        editor.write(editor.getFile());
        editor.setChanged(false);
      }
    }
    catch (IOException ioe0) {
      showException(ioe0);
    }
  }

  public void editorSaveAs(Editor editor) { // darren
    editorSaveAs(editor, _activeDocumentFrame);
  }
 
  public void editorSaveAs(Editor editor, DocumentFrame frame) { // darren
    Code.debug("editorSaveAs");
    if (frame == null) {
        return; // DARREN
    }
    
    JFileChooser chooser = new JFileChooser();
    chooser.setDialogTitle(JWP.getMessage("dialog.saveas.title"));
    chooser.setDialogType(JFileChooser.SAVE_DIALOG);
    chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

    chooser.setCurrentDirectory(new File(_documentsDirectoryPath));

    String ct = editor.getContentType();
    configureFileType(chooser, ct);

    int result = chooser.showSaveDialog(_jwpApplication);
    _documentsDirectoryPath = chooser.getCurrentDirectory().getAbsolutePath();
    
    if (result != JFileChooser.APPROVE_OPTION) {
        return;
    }

    File fileToOpen = chooser.getSelectedFile();
    if (fileToOpen.exists()) {
        int answer = JOptionPane.showConfirmDialog(_jwpApplication, 
                "Overwrite existing file?",
            "File exists.", JOptionPane.OK_CANCEL_OPTION,
            JOptionPane.WARNING_MESSAGE);
        if (answer != JOptionPane.OK_OPTION) {
            return;
        }
    }


    String mime = Mime.findContentType(fileToOpen);
      try {
        if (!ct.equals(mime)) {
          String msg = JWP.getMessage("dialog.save.warning.0");
          String query = JWP.getMessage("dialog.save.query");
          int answer = JOptionPane.showConfirmDialog(_jwpApplication, msg,
              query, JOptionPane.YES_NO_CANCEL_OPTION,
              JOptionPane.WARNING_MESSAGE);
          if (answer == JOptionPane.YES_OPTION) {
            editor.write(fileToOpen);
            editor.setFile(fileToOpen);
            frame.setTitle(fileToOpen.getName());
            editor.setChanged(false); // darren
            _jwpApplication.addToFileHistory(fileToOpen);
          }
        }
        else {
          editor.write(fileToOpen);
          editor.setFile(fileToOpen);
          frame.setTitle(fileToOpen.getName());
        }
        editor.setChanged(false); // darren
        _jwpApplication.addToFileHistory(fileToOpen);
      }
      catch (IOException ioe0) {
        showException(ioe0);
      }
  }

  private void configureFileType(JFileChooser chooser, String ct) {
    String defaultExt = "*.*";
    FileFilter filter;
    if (ct.equals("text/rtf")) {
      filter = new DynamicFileFilter("rtf", "filter.rtf.label");
      defaultExt = "*.rtf";
    }
    else if (ct.equals("text/html")) {
      filter = new DynamicFileFilter("htm html shtml",
                                     "filter.html.label");
      defaultExt = "*.html";
    }
    else if (ct.equals("text/plain")) {
      filter = new DynamicFileFilter("java c cc cpp h txt text",
                                     "filter.plain.label");
      defaultExt = "*.txt";
    }
    else {
      filter = chooser.getAcceptAllFileFilter();
      defaultExt = "*.*";
    }
    chooser.setFileFilter(filter);

    chooser.setSelectedFile(new File(defaultExt));
  }

  public void editorSaveCopy(Editor editor) {
    editorSaveCopy(editor, _activeDocumentFrame);
  }
  
  public void editorSaveCopy(Editor editor, DocumentFrame frame) {
    Code.debug("editorSaveCopy");

    JFileChooser chooser = new JFileChooser();
    chooser.setDialogTitle(JWP.getMessage("dialog.savecopy.title"));
    chooser.setDialogType(JFileChooser.SAVE_DIALOG);
    chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

    chooser.setCurrentDirectory(new File(_documentsDirectoryPath));

    String ct = editor.getContentType();
    configureFileType(chooser, ct);

    int result = chooser.showSaveDialog(_jwpApplication);
    _documentsDirectoryPath = chooser.getCurrentDirectory().getAbsolutePath();

    if (result != JFileChooser.APPROVE_OPTION) {
        return;
    }

    File fileToOpen = chooser.getSelectedFile();
    if (fileToOpen.exists()) {
        int answer = JOptionPane.showConfirmDialog(_jwpApplication, 
                "Overwrite existing file?",
            "File exists.", JOptionPane.OK_CANCEL_OPTION,
            JOptionPane.WARNING_MESSAGE);
        if (answer != JOptionPane.OK_OPTION) {
            return;
        }
    }

    String mime = Mime.findContentType(fileToOpen);
    if (!fileToOpen.getName().startsWith("*")) {
      try {
        if (!ct.equals(mime)) {
          String msg = JWP.getMessage("dialog.save.warning.0");
          String query = JWP.getMessage("dialog.save.query");
          int answer = JOptionPane.showConfirmDialog(_jwpApplication, msg,
              query, JOptionPane.YES_NO_CANCEL_OPTION,
              JOptionPane.WARNING_MESSAGE);
          if (answer == JOptionPane.YES_OPTION) {
            editor.write(fileToOpen);
          }
        }
        else {
          editor.write(fileToOpen);
        }
        editor.setChanged(false);
        _jwpApplication.addToFileHistory(fileToOpen);
      }
      catch (IOException ioe0) {
        showException(ioe0);
      }
    }
  }

  protected final DocumentFrame createDocumentFrame(File file, String title, String contentType) {
    Code.debug("Creating New Document: " + title);
    DocumentFrame doc = new DocumentFrame(_jwpApplication, contentType);
    doc.setIconifiable(true);
    doc.setResizable(true);
    doc.setMaximizable(true);
    doc.setTitle(title + " [" + contentType + "]");
    JWP.getDesktop().add(doc, doc.getName());
    cascade(doc);
    _activeDocumentFrame = doc;
    _activeDocumentFrame.activate();
    _jwpApplication.updateOpenWindowsMenu();
    if (file != null) {
      if (file.exists() & file.isFile()) {
        editorOpen(file);
      }
    }
    doc.setVisible(true);
    return doc;
  }


  protected final DocumentFrame createDocumentFrame(File file) {
    return createDocumentFrame(file,
       _newDocumentTitle + _jwpApplication.getDocumentNumber(),
       _registry.getString("MAIN", "default.content.type"));
  }


  protected final DocumentFrame createDocumentFrame(String contentType) {
    return createDocumentFrame(null,
        _newDocumentTitle + _jwpApplication.getDocumentNumber(), contentType);
  }


  protected final DocumentFrame createDocumentFrame() {
    return createDocumentFrame(
        null,
        _newDocumentTitle + (_jwpApplication.getDocumentNumber() + 1),
        _registry.getString("MAIN", "default.content.type"));
  }

  public final String[] openDocumentList() {
    Code.debug("Getting Open Document List...");
    Vector v = new Vector();
    Component[] comps = JWP.getDesktop().getComponents();
    for (int i = 0; i < comps.length; i++) {
      try {
        if (comps[i] instanceof JInternalFrame) {
          v.addElement(((JInternalFrame) comps[i]).getTitle());
        }
      }
      catch (java.lang.ClassCastException cEX) {
      }

    }
    String[] names = new String[v.size()];
    v.copyInto(names);
    return names;

  }

  public final DocumentFrame getOpenDocument(String name) {
    Component[] comps = JWP.getDesktop().getComponents();
    for (int i = 0; i < comps.length; i++) {

      if (comps[i] instanceof JInternalFrame) {
        if (((JInternalFrame) comps[i]).getTitle().equals(name)) {
          return (DocumentFrame) ((JInternalFrame) comps[i]);
        }
      } else if (comps[i] instanceof JInternalFrame.JDesktopIcon) {
          JInternalFrame.JDesktopIcon icon = (JInternalFrame.JDesktopIcon)comps[i];
          if (icon.getInternalFrame().getTitle().equals(name)) {
              try {
                icon.getInternalFrame().setIcon(false);
              } catch (PropertyVetoException err) {
                  
              }
              return (DocumentFrame) icon.getInternalFrame();
          }
      }
    }
    throw new IllegalStateException("The document " + name
        + " does not exist, or no longer exists.");
  }

  public void reactivateFrame(javax.swing.JInternalFrame f) {
      if (f == _activeDocumentFrame) {
          activateFrame(f);
      }
  }

  public void activateFrame(javax.swing.JInternalFrame f) {
    if (f != null) {
        _activeDocumentFrame = (DocumentFrame) f;
    }
    if (_jwpApplication != null) {
      switchedDocument((DocumentFrame)f, false);
    }
    if (f != null) {
        m_closeAction.setEnabled(true); // darren
        m_closeAllAction.setEnabled(true); // darren
        super.activateFrame(f);
        _activeDocumentFrame.activate();
    }
  }
  
  // darren
  public void deactivateFrame(javax.swing.JInternalFrame f) {
      if (f == _activeDocumentFrame) {
        switchedDocument(null, false);
        _jwpApplication.getEditorActionManager().deactivate(_activeDocumentFrame.getEditor());
        _jwpApplication.getEditorActionManager().enableDocumentActions(false);
        m_closeAction.setEnabled(false);
        m_closeAllAction.setEnabled(false);
      }
  }


  protected final DocumentFrame active() {
    return _activeDocumentFrame;
  }


  public final JWP getApp() {
    return _jwpApplication;
  }

  private void init() {
  }

  protected final void switchedDocument(DocumentFrame frame,
      boolean textSelected) {
    _jwpApplication.switchedDocumentFrame(frame, textSelected);
  }

  protected final void cascade(DocumentFrame dframe) {
    Dimension dsize = JWP.getDesktop().getSize();
    int targetWidth = 3 * dsize.width / 4;
    int targetHeight = 3 * dsize.height / 4;
    int nextX = 0;
    int nextY = 0;
    if (_activeDocumentFrame != null) {
      if (_activeDocumentFrame.isMaximum()) {
        try {
          dframe.setMaximum(true);
        }
        catch (java.beans.PropertyVetoException pve0) {
        }
        return;
      }
      java.awt.Point p = _activeDocumentFrame.getLocation();
      nextX = p.x;
      nextY = p.y;

      nextX += 24;
      nextY += 24;
    }

    if ((nextX + targetWidth > dsize.width)
        || (nextY + targetHeight > dsize.height)) {
      nextX = 0;
      nextY = 0;
    }
    JWP.getDesktop().getDesktopManager().setBoundsForFrame(dframe, nextX, nextY,
        targetWidth, targetHeight);
  }


  protected final class CascadeAction extends AbstractAction {
    public CascadeAction() {
      super("Cascade Windows");
    }

    public void actionPerformed(ActionEvent e) {
      cascadeAll();
    }
  }

  protected final Action getCascadeAction() {
    return new CascadeAction();
  }


  protected final void cascadeAll() {
    Component[] comps = JWP.getDesktop().getComponents();
    Dimension dsize = JWP.getDesktop().getSize();
    int targetWidth = 3 * dsize.width / 4;
    int targetHeight = 3 * dsize.height / 4;
    int nextX = 0;
    int nextY = 0;
    for (int i = 0; i < comps.length; i++) {
      if (comps[i] instanceof JInternalFrame && comps[i].isVisible()
          && !((JInternalFrame) comps[i]).isIcon()) {
        if ((nextX + targetWidth > dsize.width)
            || (nextY + targetHeight > dsize.height)) {
          nextX = 0;
          nextY = 0;
        }
        JWP.getDesktop().getDesktopManager().setBoundsForFrame(
            (JComponent) comps[i], nextX, nextY, targetWidth, targetHeight);
        ((JInternalFrame) comps[i]).toFront();
        nextX += 24;
        nextY += 24;
      }
    }
    
    if (_activeDocumentFrame != null) {
        SwingUtilities.invokeLater(new Runnable() { 
            public void run() { 
                activateFrame(_activeDocumentFrame); // DARREN
            }
        });
    }
    
  }

  private CloseAction m_closeAction = new CloseAction(); // darren
  private CloseAllAction m_closeAllAction = new CloseAllAction(); // darren
  protected final class CloseAction extends AbstractAction {
    public CloseAction() {
      super("Close");
    }

    public void actionPerformed(ActionEvent e) {
      /*
        if (closeActiveDocument() && active() != null) {
          try {
              active().setClosed(true); // darren
          } catch (PropertyVetoException err) {
              
          }
      }*/
        
        if (active() != null) { // darren
            try {
                active().setClosed(true);
          } catch (PropertyVetoException err) {

          }
        }
    }
  }

  protected final Action getCloseAction() {
    return m_closeAction; // darren
  }

  protected final boolean closeDocument(DocumentFrame frame) {
    if (frame == null) {
        return true; // DARREN
    }
      Editor ed = frame.getEditor();
      if (ed == null) {
          //active().dispose();
          return true; // Darren
      }
      
    if (ed.isChanged()) {
      switch (JOptionPane.showConfirmDialog(_jwpApplication,
          "Document Changed!\n\"" + frame.getTitle()
              + "\"\nDo you want to save the changes?", "Save Changes?",
          JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE)) {
      case JOptionPane.YES_OPTION:
        if (ed.isNew()) {
          editorSaveAs(ed, frame);
        }
        else {
          editorSave(ed, frame);
        }
        if (!ed.isChanged()) {
          //active().dispose();
        }
        return !ed.isChanged();
      case JOptionPane.NO_OPTION:
        //active().dispose();
        return true;
      default:
        return false;
      }
    }
    else {
      //System.exit(0);
      //active().dispose();
      return true; // darren
    }
  }

  
  protected final boolean closeActiveDocument() {
    return closeDocument(active());
  }

  protected final class CloseAllAction extends AbstractAction {
    public CloseAllAction() {
      super("Close All");
    }

    public void actionPerformed(ActionEvent e) {
      closeAllDocuments();
    }
  }

  protected final Action getCloseAllAction() {
    return m_closeAllAction;
  }


  protected final boolean closeAllDocuments() {
    Component[] comps = JWP.getDesktop().getComponents();
    for (int i = 0; i < comps.length; i++) {
      if (comps[i] instanceof DocumentFrame &
          comps[i].isVisible() &
          ((JInternalFrame) comps[i]).isClosable()) {

        DocumentFrame actOnDoc = ((DocumentFrame) comps[i]);
        actOnDoc.activate();
        try {
          actOnDoc.setClosed(true);
        }
        catch (PropertyVetoException err) {
            // Close was cancelled. (DARREN)
            return false;
        }
        catch (Exception err) {
            JOptionPane.showMessageDialog(_jwpApplication, "Close error: " + err.getMessage(), "Pause", 
                                    JOptionPane.INFORMATION_MESSAGE);
        }
        catch (Throwable t) {
            JOptionPane.showMessageDialog(_jwpApplication, "Close error", "Pause", 
                                    JOptionPane.INFORMATION_MESSAGE);
            
        }
      }
    }
    _activeDocumentFrame = null;
    return true;
  }


  protected final class MinimizeAction extends AbstractAction {
    public MinimizeAction() {
      super("Minimize Windows");
    }

    public void actionPerformed(ActionEvent e) {
      minimizeAll();
    }
  }

  protected final Action getMinimizeAction() {
    return new MinimizeAction();
  }


  protected final void minimizeAll() {
    Component[] comps = JWP.getDesktop().getComponents();
    for (int i = 0; i < comps.length; i++) {
      if (comps[i] instanceof JInternalFrame && comps[i].isVisible()
          && !((JInternalFrame) comps[i]).isIcon()
          && ((JInternalFrame) comps[i]).isIconifiable()) {
        try {
          ((JInternalFrame) comps[i]).setIcon(true);
        }
        catch (java.beans.PropertyVetoException pve0) {
        }
      }
    }
  }


  protected final class TileAction extends AbstractAction {
    public TileAction() {
      super("Tile Windows");
    }

    public void actionPerformed(ActionEvent e) {
      tileAll();
    }
  }

  protected final Action getTileAction() {
    return new TileAction();
  }


  protected final void tileAll() {
    if (JWP.getDesktop().getDesktopManager() == null) {
      return;
    }
    Component[] comps = JWP.getDesktop().getComponents();
    Component comp;
    int count = 0;

    for (int i = 0; i < comps.length; i++) {
      comp = comps[i];
      if (comp instanceof JInternalFrame && comp.isVisible()
          && !((JInternalFrame) comp).isIcon()) {
        count++;
      }
    }
    if (count != 0) {
      double root = Math.sqrt(count);
      int rows = (int) root;
      int columns = count / rows;
      int spares = count - (columns * rows);
      Dimension paneSize = JWP.getDesktop().getSize();
      int columnWidth = paneSize.width / columns;

      int availableHeight = paneSize.height - 48;
      int mainHeight = availableHeight / rows;
      int smallerHeight = availableHeight / (rows + 1);
      int rowHeight = mainHeight;
      int x = 0;
      int y = 0;
      int thisRow = rows;
      int normalColumns = columns - spares;
      for (int i = comps.length - 1; i >= 0; i--) {
        comp = comps[i];
        if (comp instanceof JInternalFrame && comp.isVisible() &&
            !((JInternalFrame) comp).isIcon()) {
          DesktopManager dm = JWP.getDesktop().getDesktopManager();
          dm.setBoundsForFrame((JComponent) comp, x, y,
                               columnWidth, rowHeight);
          y += rowHeight;
          if (--thisRow == 0) {
            y = 0;
            x += columnWidth;

            if (--normalColumns <= 0) {
              thisRow = rows + 1;
              rowHeight = smallerHeight;
            }
            else {
              thisRow = rows;
            }
          }
        }
      }
    }
  }

  private void showException(Exception ex) {
    String msg = "Exception\n" + ex.getMessage();
    JOptionPane.showMessageDialog(_jwpApplication, msg, "Exception",
                                  JOptionPane.ERROR_MESSAGE);
  }

  private JWP getParent() {
    return _jwpApplication;
  }
}
